<template>
    <div loading="loading" ref="terminal"></div>
</template>
<script setup lang="ts">
import { reactive, toRefs, onBeforeMount, onMounted, ref, watch } from 'vue'
import { debounce } from 'lodash'
import { Terminal } from "xterm";
import "xterm/css/xterm.css";
import { FitAddon } from 'xterm-addon-fit'
import { AttachAddon } from 'xterm-addon-attach'
//import { TerminalInfo } from "@/entity/entitys"
const terminal = ref();
const props = defineProps({
    terminalDetail: Object,
    type: String
});
let fitAddon = ref();

let first = ref(true);
let loading = ref<boolean>(true);
let terminalSocket = ref();
let term:Terminal = reactive(new Terminal({
        lineHeight: 1.2,
        fontSize: 12,
        fontFamily: "Monaco, Menlo, Consolas, 'Courier New', monospace",
        theme: {
            background: '#181d28',
        },
        // 光标闪烁
        cursorBlink: true,
        cursorStyle: 'underline',
        scrollback: 100,
        tabStopWidth: 4,
        
    }));


const runRealTerminal = () => {
    loading.value = false;
}

const onWSReceive = (message: { data: string; }) => {
    // 首次接收消息,发送给后端，进行同步适配
    if (first.value === true) {
        first.value = false;
        resizeRemoteTerminal();
    }
    const data = JSON.parse(message.data);
    term?.element && term.focus()
    term?.write(data.Data)
}

const errorRealTerminal = (ex: Event) => {
    let message = ex.type
    if (!message) message = 'disconnected'
    term?.write(`\x1b[31m${message}\x1b[m\r\n`)
    console.log("err");
}
const closeRealTerminal = () => {
    console.log("close");
}

const createWS = () => {
    try {
        const url = 'ws://127.0.0.1:5555'
        terminalSocket.value = new WebSocket(url);
        terminalSocket.value.writeln("\x1b[1;1;32mwellcom to web terminal!\x1b[0m");
        terminalSocket.value.onopen = runRealTerminal;
        terminalSocket.value.onmessage = onWSReceive;
        terminalSocket.value.onclose = closeRealTerminal;
        terminalSocket.value.onerror = errorRealTerminal;
    } catch (error) {
        console.log("------- error " + error)
    }

}
const initWS = () => {
    if (!terminalSocket.value) {
        createWS();
    }
    if (terminalSocket.value && terminalSocket.value.readyState > 1) {
        terminalSocket.value.close();
        createWS();
    }
}
// 发送给后端,调整后端终端大小,和前端保持一致,不然前端只是范围变大了,命令还是会换行
const resizeRemoteTerminal = () => {
    const { cols, rows } = term
    if (isWsOpen()) {
        terminalSocket.value?.send(JSON.stringify({
            Op: 'resize',
            Cols: cols,
            Rows: rows,
        }))
    }
}
const initTerm = () => {
    const attachAddon = new AttachAddon(terminalSocket.value)
    fitAddon.value = new FitAddon()
    // term = new Terminal({
    //     lineHeight: 1.2,
    //     fontSize: 12,
    //     fontFamily: "Monaco, Menlo, Consolas, 'Courier New', monospace",
    //     theme: {
    //         background: '#181d28',
    //     },
    //     // 光标闪烁
    //     cursorBlink: true,
    //     cursorStyle: 'underline',
    //     scrollback: 100,
    //     tabStopWidth: 4,
    // });
    // term.prompt = (_: any) => {
    //     term.write("\r\n\x1b[33m$\x1b[0m ")
    //   }
    // term.prompt()
    term.write("\r\n\x1b[33m$\x1b[0m ")
    term.onKey(e => {
        console.log("========term: ",term)
        const printable = !e.domEvent.altKey &&  !e.domEvent.ctrlKey && !e.domEvent.metaKey
        console.log("========e.domEvent.keyCode: ",e.domEvent.keyCode)
        console.log("========e: ",e.key)
        console.log("========: ",e.domEvent)
        if (e.domEvent.key === "Enter") {
            // term.prompt() { key: string, domEvent: KeyboardEvent }
        } else if (e.domEvent.key === "Backspace") { // back 删除的情况
          //if (term.textarea.buffer.x > 2) {
            term.write('\b \b')
          //}
        } else if (printable) {
            term.write(e.key)
        }
        console.log(1,'print', e.key)
      })
      term.onData((key: string ) => {  // 粘贴的情况
        if(key.length > 1) term.write(key)
      })
    term.writeln("Welcome to \x1b[1;32mMyTool\x1b[0m.")
    term.writeln('This is Web Terminal of Modb; Good Good Study, Day Day Up.')
    term.loadAddon(fitAddon.value);
    term.loadAddon(attachAddon);
    term.open(terminal.value);
    // 不能初始化的时候fit,需要等terminal准备就绪,可以设置延时操作
    setTimeout(() => {
        fitAddon.value.fit();
        term.focus()
    }, 2)

    //const socket = new WebSocket('ws://localhost:8898/ws')
    //const attachAddon = new AttachAddon(terminalSocket.value)
    // const fitAddon = new FitAddon()
    // term.loadAddon(attachAddon)
    // term.loadAddon(fitAddon)
    //   term.open(xterm)
    //   fitAddon.fit()
    //   term.focus()
}
// 是否连接中0 1 2 3 
const isWsOpen = () => {
    const readyState = terminalSocket.value && terminalSocket.value.readyState;
    return readyState === 1
}
const fitTerm = () => {
    // 窗口大小改变时，触发xterm的resize方法使自适应
    fitAddon.value.fit();
}
const onResize = debounce(() => fitTerm(), 800);

const termData = () => {
    // 输入与粘贴的情况,onData不能重复绑定,不然会发送多次
    term?.onData((data: any) => {
        if (isWsOpen()) {
            terminalSocket.value?.send(
                JSON.stringify({
                    Op: 'stdin',
                    Data: data,
                })
            );
        }
    });
}
const onTerminalResize = () => {
    //Window.addEventListener() 方法，事件监听
    window.addEventListener("resize", onResize);
}
const removeResizeListener = () => {
    window.removeEventListener("resize", onResize);
}
//监听类型变化，重置term
watch(() => props.type, () => {
    first.value = true;
    loading.value = true;
    terminalSocket.value = null;
    initWS();
    // 重置
    term.reset();
})

onMounted(() => {
    initWS();
    initTerm();
    termData();
    onTerminalResize();
})
onBeforeMount(() => {
    console.log(onBeforeMount)
    removeResizeListener();
    terminalSocket.value && terminalSocket.value.close();
})
</script>
<style lang="scss" scoped>
#terminal {
    width: 100%;
    height: 100%;
}
</style>